ποΈGitΠ―ΡΠ°ποΈ
.github/workflows/models_issue_triage.yml d9b024acde4db05002d2f413cfcffc5fd19927d5 (d9b024ac) Text, 10.23 KB
Tff7b72nameTb4b4b4: Ta5d6ffIssueTa5d6ff Ta5d6ffTriageTa5d6ff Ta5d6ff(Models)
Tff7b72onTb4b4b4:
Tff7b72workflow_dispatchTb4b4b4:
Tff7b72permissionsTb4b4b4:
Tff7b72issuesTb4b4b4: Ta5d6ffwrite
Tff7b72modelsTb4b4b4: Ta5d6ffread
Tff7b72concurrencyTb4b4b4:
Tff7b72groupTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffgithub.workflowTa5d6ff Ta5d6ff}}-${{Ta5d6ff Ta5d6ffgithub.event.issue.numberTa5d6ff Ta5d6ff}}
Tff7b72cancel-in-progressTb4b4b4: Ta5d6fftrue
Tff7b72jobsTb4b4b4:
Tff7b72triageTb4b4b4:
Tff7b72ifTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffgithub.repositoryTa5d6ff Ta5d6ff==Ta5d6ff Ta5d6ff'meshtastic/Meshtastic-Android'Ta5d6ff Ta5d6ff&&Ta5d6ff Ta5d6ffgithub.event.issue.user.typeTa5d6ff Ta5d6ff!=Ta5d6ff Ta5d6ff'Bot'Ta5d6ff Ta5d6ff}}
Tff7b72runs-onTb4b4b4: Ta5d6ffubuntu-24.04-arm
Tff7b72stepsTb4b4b4:
T8b949e# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
T8b949e# Step 1: Quality check (spam/AI-slop detection) - runs first, exits early if spam
T8b949e# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Tb4b4b4- Tff7b72nameTb4b4b4: Ta5d6ffDetectTa5d6ff Ta5d6ffspamTa5d6ff Ta5d6fforTa5d6ff Ta5d6fflow-qualityTa5d6ff Ta5d6ffcontent
Tff7b72usesTb4b4b4: Ta5d6ffactions/ai-inference@v2
Tff7b72idTb4b4b4: Ta5d6ffquality
Tff7b72continue-on-errorTb4b4b4: Ta5d6fftrue
Tff7b72withTb4b4b4:
Tff7b72max-tokensTb4b4b4: Ta5d6ff20
Tff7b72promptTb4b4b4: Tb4b4b4|
Tff7b72Is this GitHub issue spam, AI-generated slop, or low quality?
Tff7b72Title: ${{ github.event.issue.title }}
Tff7b72Body: ${{ github.event.issue.body }}
Tff7b72Respond with exactly one of: spam, ai-generated, needs-review, ok
Tff7b72system-promptTb4b4b4: Ta5d6ffYouTa5d6ff Ta5d6ffdetectTa5d6ff Ta5d6ffspamTa5d6ff Ta5d6ffandTa5d6ff Ta5d6fflow-qualityTa5d6ff Ta5d6ffcontributions.Ta5d6ff Ta5d6ffBeTa5d6ff Ta5d6ffconservativeTa5d6ff Ta5d6ff-Ta5d6ff Ta5d6ffonlyTa5d6ff Ta5d6ffflagTa5d6ff Ta5d6ffobviousTa5d6ff Ta5d6ffspamTa5d6ff Ta5d6fforTa5d6ff Ta5d6ffAITa5d6ff Ta5d6ffslop.
Tff7b72modelTb4b4b4: Ta5d6ffopenai/gpt-4o-mini
Tb4b4b4- Tff7b72nameTb4b4b4: Ta5d6ffApplyTa5d6ff Ta5d6ffqualityTa5d6ff Ta5d6fflabelTa5d6ff Ta5d6ffifTa5d6ff Ta5d6ffneeded
Tff7b72ifTb4b4b4: Ta5d6ffsteps.quality.outputs.responseTa5d6ff Ta5d6ff!=Ta5d6ff Ta5d6ff''Ta5d6ff Ta5d6ff&&Ta5d6ff Ta5d6ffsteps.quality.outputs.responseTa5d6ff Ta5d6ff!=Ta5d6ff Ta5d6ff'ok'
Tff7b72usesTb4b4b4: Ta5d6ffactions/github-script@v9
Tff7b72envTb4b4b4:
Tff7b72QUALITY_LABELTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffsteps.quality.outputs.responseTa5d6ff Ta5d6ff}}
Tff7b72withTb4b4b4:
Tff7b72scriptTb4b4b4: Tb4b4b4|
Tff7b72const label = (process.env.QUALITY_LABEL || '').trim().toLowerCase();
Tff7b72const labelMeta = {
Tff7b72'spam': { color: 'd73a4a', description: 'Possible spam' },
Tff7b72'ai-generated': { color: 'fbca04', description: 'Possible AI-generated low-quality content' },
Tff7b72'needs-review': { color: 'f9d0c4', description: 'Needs human review' },
Tff7b72};
Tff7b72const meta = labelMeta[label];
Tff7b72if (!meta) return;
Tff7b72// Ensure label exists
Tff7b72try {
Tff7b72await github.rest.issues.getLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label });
Tff7b72} catch (e) {
Tff7b72if (e.status !== 404) throw e;
Tff7b72await github.rest.issues.createLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label, color: meta.color, description: meta.description });
Tff7b72}
Tff7b72// Apply label
Tff7b72await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.payload.issue.number, labels: [label] });
Tff7b72// Set output to skip remaining steps
Tff7b72core.setOutput('is_spam', 'true');
T8b949e# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
T8b949e# Step 2: Duplicate detection - only if not spam
T8b949e# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Tb4b4b4- Tff7b72nameTb4b4b4: Ta5d6ffDetectTa5d6ff Ta5d6ffduplicateTa5d6ff Ta5d6ffissues
Tff7b72ifTb4b4b4: Ta5d6ffsteps.quality.outputs.responseTa5d6ff Ta5d6ff==Ta5d6ff Ta5d6ff'ok'Ta5d6ff Ta5d6ff||Ta5d6ff Ta5d6ffsteps.quality.outputs.responseTa5d6ff Ta5d6ff==Ta5d6ff Ta5d6ff''
Tff7b72usesTb4b4b4: Ta5d6ffpelikhan/action-genai-issue-dedup@bdb3b5d9451c1090ffcdf123d7447a5e7c7a2528 T8b949e# v0.0.19
Tff7b72withTb4b4b4:
Tff7b72github_tokenTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffsecrets.GITHUB_TOKENTa5d6ff Ta5d6ff}}
T8b949e# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
T8b949e# Step 3: Completeness check + auto-labeling (combined into one AI call)
T8b949e# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Tb4b4b4- Tff7b72nameTb4b4b4: Ta5d6ffDetermineTa5d6ff Ta5d6ffifTa5d6ff Ta5d6ffcompletenessTa5d6ff Ta5d6ffcheckTa5d6ff Ta5d6ffshouldTa5d6ff Ta5d6ffbeTa5d6ff Ta5d6ffskipped
Tff7b72ifTb4b4b4: Ta5d6ffsteps.quality.outputs.responseTa5d6ff Ta5d6ff==Ta5d6ff Ta5d6ff'ok'Ta5d6ff Ta5d6ff||Ta5d6ff Ta5d6ffsteps.quality.outputs.responseTa5d6ff Ta5d6ff==Ta5d6ff Ta5d6ff''
Tff7b72usesTb4b4b4: Ta5d6ffactions/github-script@v9
Tff7b72idTb4b4b4: Ta5d6ffcheck-skip
Tff7b72withTb4b4b4:
Tff7b72scriptTb4b4b4: Tb4b4b4|
Tff7b72const title = (context.payload.issue.title || '').toLowerCase();
Tff7b72const labels = (context.payload.issue.labels || []).map(label => label.name);
Tff7b72const hasFeatureRequest = title.includes('feature request');
Tff7b72const hasEnhancement = labels.includes('enhancement');
Tff7b72const shouldSkip = hasFeatureRequest && hasEnhancement;
Tff7b72core.setOutput('should_skip', shouldSkip ? 'true' : 'false');
Tb4b4b4- Tff7b72nameTb4b4b4: Ta5d6ffAnalyzeTa5d6ff Ta5d6ffissueTa5d6ff Ta5d6ffcompletenessTa5d6ff Ta5d6ffandTa5d6ff Ta5d6ffdetermineTa5d6ff Ta5d6fflabels
Tff7b72ifTb4b4b4: Ta5d6ff(steps.quality.outputs.responseTa5d6ff Ta5d6ff==Ta5d6ff Ta5d6ff'ok'Ta5d6ff Ta5d6ff||Ta5d6ff Ta5d6ffsteps.quality.outputs.responseTa5d6ff Ta5d6ff==Ta5d6ff Ta5d6ff'')Ta5d6ff Ta5d6ff&&Ta5d6ff Ta5d6ffsteps.check-skip.outputs.should_skipTa5d6ff Ta5d6ff!=Ta5d6ff Ta5d6ff'true'
Tff7b72usesTb4b4b4: Ta5d6ffactions/ai-inference@v2
Tff7b72idTb4b4b4: Ta5d6ffanalysis
Tff7b72continue-on-errorTb4b4b4: Ta5d6fftrue
Tff7b72withTb4b4b4:
Tff7b72promptTb4b4b4: Tb4b4b4|
Tff7b72Analyze this GitHub issue for the Meshtastic Android app and determine if it needs labels.
Tff7b72If this looks like a bug in the Android app (crash, ANR, UI glitch, connection failure, Bluetooth issues, notification problems, map issues), request app logs and explain how to get them:
Tff7b72Android app debug logs:
Tff7b72- Open the Meshtastic app, go to Settings > Debug > Save Logs
Tff7b72- Reproduce the problem, then share/attach the exported log file
Tff7b72Android logcat (if app logs are insufficient):
Tff7b72- Connect phone via USB with USB debugging enabled
Tff7b72- Run: adb logcat -s Meshtastic:* *:E
Tff7b72- Reproduce the problem, then copy/paste the relevant output
Tff7b72Also request key context if missing: Android version, phone model, app version, Meshtastic device model, firmware version, connection type (BLE/USB/TCP), steps to reproduce, expected vs actual.
Tff7b72Respond ONLY with JSON:
Tff7b72{
Tff7b72"complete": true|false,
Tff7b72"comment": "Your helpful comment requesting missing info, or empty string if complete",
Tff7b72"label": "needs-logs" | "needs-info" | "none"
Tff7b72}
Tff7b72Use "needs-logs" if this is an app bug AND no logs are attached.
Tff7b72Use "needs-info" if basic info like firmware version or steps to reproduce are missing.
Tff7b72Use "none" if the issue is complete or is a feature request.
Tff7b72Title: ${{ github.event.issue.title }}
Tff7b72Body: ${{ github.event.issue.body }}
Tff7b72system-promptTb4b4b4: Ta5d6ffYouTa5d6ff Ta5d6ffareTa5d6ff Ta5d6ffaTa5d6ff Ta5d6ffhelpfulTa5d6ff Ta5d6ffassistantTa5d6ff Ta5d6ffthatTa5d6ff Ta5d6fftriagesTa5d6ff Ta5d6ffGitHubTa5d6ff Ta5d6ffissues.Ta5d6ff Ta5d6ffBeTa5d6ff Ta5d6ffconservativeTa5d6ff Ta5d6ffwithTa5d6ff Ta5d6fflabels.
Tff7b72modelTb4b4b4: Ta5d6ffopenai/gpt-4o-mini
Tb4b4b4- Tff7b72nameTb4b4b4: Ta5d6ffProcessTa5d6ff Ta5d6ffanalysisTa5d6ff Ta5d6ffresult
Tff7b72ifTb4b4b4: Ta5d6ff(steps.quality.outputs.responseTa5d6ff Ta5d6ff==Ta5d6ff Ta5d6ff'ok'Ta5d6ff Ta5d6ff||Ta5d6ff Ta5d6ffsteps.quality.outputs.responseTa5d6ff Ta5d6ff==Ta5d6ff Ta5d6ff'')Ta5d6ff Ta5d6ff&&Ta5d6ff Ta5d6ffsteps.check-skip.outputs.should_skipTa5d6ff Ta5d6ff!=Ta5d6ff Ta5d6ff'true'Ta5d6ff Ta5d6ff&&Ta5d6ff Ta5d6ffsteps.analysis.outputs.responseTa5d6ff Ta5d6ff!=Ta5d6ff Ta5d6ff''
Tff7b72usesTb4b4b4: Ta5d6ffactions/github-script@v9
Tff7b72idTb4b4b4: Ta5d6ffprocess
Tff7b72envTb4b4b4:
Tff7b72AI_RESPONSETb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffsteps.analysis.outputs.responseTa5d6ff Ta5d6ff}}
Tff7b72withTb4b4b4:
Tff7b72scriptTb4b4b4: Tb4b4b4|
Tff7b72const raw = (process.env.AI_RESPONSE || '').trim();
Tff7b72let complete = false;
Tff7b72let comment = '';
Tff7b72let label = 'none';
Tff7b72try {
Tff7b72const parsed = JSON.parse(raw);
Tff7b72complete = !!parsed.complete;
Tff7b72comment = (parsed.comment ?? '').toString().trim();
Tff7b72label = (parsed.label ?? 'none').toString().trim().toLowerCase();
Tff7b72} catch {
Tff7b72// If JSON parse fails, treat as incomplete with raw response as comment
Tff7b72complete = false;
Tff7b72comment = raw;
Tff7b72label = 'none';
Tff7b72}
Tff7b72// Validate label
Tff7b72const allowedLabels = new Set(['needs-logs', 'needs-info', 'none']);
Tff7b72if (!allowedLabels.has(label)) label = 'none';
Tff7b72core.setOutput('should_comment', (!complete && comment.length > 0) ? 'true' : 'false');
Tff7b72core.setOutput('comment_body', comment);
Tff7b72core.setOutput('label', label);
Tb4b4b4- Tff7b72nameTb4b4b4: Ta5d6ffApplyTa5d6ff Ta5d6fftriageTa5d6ff Ta5d6fflabel
Tff7b72ifTb4b4b4: Ta5d6ffsteps.process.outputs.labelTa5d6ff Ta5d6ff!=Ta5d6ff Ta5d6ff''Ta5d6ff Ta5d6ff&&Ta5d6ff Ta5d6ffsteps.process.outputs.labelTa5d6ff Ta5d6ff!=Ta5d6ff Ta5d6ff'none'
Tff7b72usesTb4b4b4: Ta5d6ffactions/github-script@v9
Tff7b72envTb4b4b4:
Tff7b72LABEL_NAMETb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffsteps.process.outputs.labelTa5d6ff Ta5d6ff}}
Tff7b72withTb4b4b4:
Tff7b72scriptTb4b4b4: Tb4b4b4|
Tff7b72const label = process.env.LABEL_NAME;
Tff7b72const labelMeta = {
Tff7b72'needs-logs': { color: 'cfd3d7', description: 'Device logs requested for triage' },
Tff7b72'needs-info': { color: 'f9d0c4', description: 'More information requested for triage' },
Tff7b72};
Tff7b72const meta = labelMeta[label];
Tff7b72if (!meta) return;
Tff7b72// Ensure label exists
Tff7b72try {
Tff7b72await github.rest.issues.getLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label });
Tff7b72} catch (e) {
Tff7b72if (e.status !== 404) throw e;
Tff7b72await github.rest.issues.createLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label, color: meta.color, description: meta.description });
Tff7b72}
Tff7b72// Apply label
Tff7b72await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.payload.issue.number, labels: [label] });
Tb4b4b4- Tff7b72nameTb4b4b4: Ta5d6ffCommentTa5d6ff Ta5d6ffonTa5d6ff Ta5d6ffissue
Tff7b72ifTb4b4b4: Ta5d6ffsteps.process.outputs.should_commentTa5d6ff Ta5d6ff==Ta5d6ff Ta5d6ff'true'
Tff7b72usesTb4b4b4: Ta5d6ffactions/github-script@v9
Tff7b72envTb4b4b4:
Tff7b72COMMENT_BODYTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffsteps.process.outputs.comment_bodyTa5d6ff Ta5d6ff}}
Tff7b72withTb4b4b4:
Tff7b72scriptTb4b4b4: Tb4b4b4|
Tff7b72await github.rest.issues.createComment({
Tff7b72owner: context.repo.owner,
Tff7b72repo: context.repo.repo,
Tff7b72issue_number: context.payload.issue.number,
Tff7b72body: process.env.COMMENT_BODY
Tff7b72});
Served by rngit 1.5.2 - Generated in 0.09s